package com.markyao.service.impl;

import com.markyao.recos.regist.RecosRegistConfig;
import com.markyao.service.AbstractViewService;
import com.markyao.service.RecosViewService;
import com.markyao.utils.LocalUtils;
import com.markyao.vo.Result;
import com.markyao.vo.pojo.AppBean;
import com.markyao.vo.pojo.ServiceBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import static com.markyao.service.redis.UtilsKeys.*;

@Slf4j(topic = "m.RecosViewService")
@Service
public class RecosViewServiceImpl extends AbstractViewService implements RecosViewService {
    @Autowired
    @Qualifier("serverRegistryMap")
    Map<String, Map<String,String>>serverRegistryMap;
    @Autowired
    @Qualifier("providersMap")
    Map<String,Map<String,String>>providersMap;
    @Autowired
    @Qualifier("heartBeatMap")
    Map<String,Long>heartBeatMap;
    @Autowired
    @Qualifier("urlMap")
    Map<String,String>urlMap;
    @Autowired
    @Qualifier("serviceRegistryMap")
    Map<String,Map<String,String>>serviceRegistryMap;
    @Autowired
    @Qualifier("connectSet")
    Map<String, Set<String>> connectSet;
    @Autowired
    @Qualifier("refrenceRegistrySet")
    Map<String,Set<String>>refrenceRegistrySet;
    @Autowired
    @Qualifier("killConnectKeys")
    Map<String,Set<String>>killConnectKeys;
    @Autowired
    @Qualifier("reconnectKeys")
    Map<String,Set<String>>reconnectKeys;
    @Autowired
    @Qualifier("healthMap")
    Map<String,String> healthMap;

    @Autowired
    RecosRegistConfig recosRegistConfig;
    @Autowired
    @Qualifier("leaderMetadata")
    ConcurrentHashMap<String,Object> leaderMap;
    @Autowired
    RestTemplate restTemplate;


    @Override
    protected void refreshAppbeansBuf(List<AppBean> appbeanBuffers) {
        for (Map.Entry<String, Map<String, String>> e : serverRegistryMap.entrySet()) {
            AppBean appBean=new AppBean();
            Map<String, String> map = e.getValue();
            String appName = map.get(APPNAME);
            String weight = map.get(WEIGHT);
            String url = map.get(URL);
            String alive=isAlive(appName);
            appBean.setAppName(appName);
            appBean.setWeight(weight);
            appBean.setUrl(url);
            appBean.setAlive(alive);
            appbeanBuffers.add(appBean);
        }
    }

    @Override
    protected String getHealth(String appName) {
        boolean hasKey = heartBeatMap.containsKey(appName);
        String health = healthMap.get(appName);
        if (hasKey && StringUtils.hasText(health)){
            return health;
        }
        return deadValue;
    }

    private String isAlive(String appName){
        boolean hasKey = heartBeatMap.containsKey(appName);
        String health = healthMap.get(appName);
        if (hasKey && StringUtils.hasText(health)){
            return health;
        }
        return deadValue;
    }
    @Override
    protected void refreshServicesBuffers(List<ServiceBean> servicesBuffers) {
        Set<String> providerKeySet = providersMap.keySet();

        for (String providerInterfaca : providerKeySet) {
            Map<String, String> urlWeight = providersMap.get(providerInterfaca);
            for (String url : urlWeight.keySet()) {
                String appName = urlMap.get(url);
                ServiceBean serviceBean=new ServiceBean();
                serviceBean.setInterfaceName(providerInterfaca);
                serviceBean.setProviderName(appName);
                serviceBean.setInstanceName(serviceRegistryMap.get(appName).get(providerInterfaca));
                serviceBean.setDetails("...");
                servicesBuffers.add(serviceBean);
            }

        }
    }

    @Override
    protected String getUrl(String appName) {
        return serverRegistryMap.get(appName).get(URL);
    }

    @Override
    protected Boolean isHeartBeat(String heartBeatKey) {
        return heartBeatMap.containsKey(heartBeatKey);
    }

    @Override
    protected Set<String> getConnectSetByAppName(String appName) {
        return connectSet.get(appName);
    }

    @Override
    protected Set<String> getConnectSetByKey() {
        return connectSet.keySet();
    }

    @Override
    protected Set<String> getConnectSetByKey(String key) {
        return connectSet.get(key);
    }

    @Override
    protected Boolean isConnecting(String appName) {
        return connectSet.containsKey(appName);
    }

    @Override
    protected Set<String> getRefrenceSetByAppName(String appName) {
        return refrenceRegistrySet.get(appName);
    }

    @Override
    protected Boolean isRefrence(String appName) {
        return refrenceRegistrySet.containsKey(appName);
    }

    @Override
    protected Map<Object, Object> getBeanMapFromServicesByAppName(String appName) {
        Map<String, String> map = serviceRegistryMap.get(appName);
        return copyMap(map);
    }

    @Override
    protected Map<Object, Object> getBeanMapFromServersByAppName(String appName) {
        Map<String, String> map = serverRegistryMap.get(appName);
        return copyMap(map);
    }
    private Map<Object, Object> copyMap(Map<String, String> map) {
        Map<Object,Object>mp=new HashMap<>();
        for (Map.Entry<String, String> e : map.entrySet()) {
            mp.put(e.getKey(),e.getValue());
        }
        return mp;
    }
    @Override
    protected Boolean isProvider(String appName) {
        return serviceRegistryMap.containsKey(appName);
    }

    @Override
    public void closeConnect(String curApp, String tarApp) {
        Set<String> set = killConnectKeys.getOrDefault(curApp, new HashSet<>());
        set.add(tarApp);
        killConnectKeys.put(curApp,set);
    }

    @Override
    public void reConnect(String curApp, String tarApp) {
        Set<String> set = reconnectKeys.getOrDefault(curApp, new HashSet<>());
        set.add(tarApp);
        reconnectKeys.put(curApp,set);
    }


    @Override
    public Result selectInfo() {
        HashMap<String,Object>result=new HashMap<>();

        boolean group = recosRegistConfig.isGroup();
        int mode=group?1:0;
        result.put("mode",mode);

        if (!group){
            return Result.success(result);
        }
        Map<String,Object>info=new HashMap<>();


        info.put("address",recosRegistConfig.getHost()+":"+recosRegistConfig.getPort());
        info.put("role",recosRegistConfig.isLeader()?"leader":"follower");

        int cpucore = LocalUtils.getCpucore();
        String memory = LocalUtils.getMemory();
        boolean reachable = LocalUtils.isReachable();

        String baseInfo="\n"+
                "CPU核心数: "+cpucore+
                "\n内存情况 :"+memory+
                "\n网络连通情况: "+(reachable?"网络正常":"网络连通异常");
        info.put("baseInfo",baseInfo);
        info.put("groupNum",recosRegistConfig.getGroupAds().length+1);

        result.put("info",info);

        List<Map<String,Object>>groupInfos=new ArrayList<>();

        for (String groupAd : recosRegistConfig.getGroupAds()) {
            Map<String,Object>groupInfo=new HashMap<>();
            groupInfo.put("address",groupAd);
            String[] split = groupAd.split(":");
            if (leaderMap.get("host").equals(split[0]) && leaderMap.get("port").toString().equals(split[1])){
                groupInfo.put("role","leader");
            }else {
                groupInfo.put("role","follower");
            }
            MultiValueMap<String,String> headrs=new LinkedMultiValueMap<>();
            headrs.add("Authorization",recosRegistConfig.getTokenMap().get(groupAd));
            HttpEntity httpEntity=new HttpEntity(null,headrs);
            String health="h";
            try {
                ResponseEntity<String> response =
                        restTemplate.exchange(groupAd + "/recos/group/health", HttpMethod.GET, httpEntity, String.class);
                String h = response.getBody();
                health=h;
            } catch (Exception e) {
                health="d";
            }
            groupInfo.put("health",health);
            groupInfos.add(groupInfo);
        }
        result.put("groupInfos",groupInfos);

        return Result.success(result);
    }

    @Override
    public Result selectInfo0() {

        return null;
    }
}
